﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="MimeTypes.cs" company="">
//   
// </copyright>
// <summary>
//   The mime types.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Libium.Core
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    /// <summary>
    ///   The mime types.
    /// </summary>
    public static class MimeTypes
    {
        #region Static Fields

        /// <summary>
        ///   The av interleave.
        /// </summary>
        public static readonly MimeType AVInterleave = new MimeType
            {
               Name = "QuickTime", ContentType = "video/x-msvideo", FileExtensions = new[] { "avi" } 
            };

        /// <summary>
        ///   The bmp.
        /// </summary>
        public static readonly MimeType Bmp = new MimeType
            {
               Name = "Bitmap Image File", ContentType = "image/bmp", FileExtensions = new[] { FileExtensions.Bmp } 
            };

        /// <summary>
        ///   The doc.
        /// </summary>
        public static readonly MimeType Doc = new MimeType
            {
               Name = "Microsoft Word", ContentType = "application/msword", FileExtensions = new[] { "doc" } 
            };

        /// <summary>
        ///   The emf.
        /// </summary>
        public static readonly MimeType Emf = new MimeType
            {
               Name = "Emf", ContentType = string.Empty, FileExtensions = new[] { FileExtensions.Emf } 
            };

        /// <summary>
        ///   The exif.
        /// </summary>
        public static readonly MimeType Exif = new MimeType
            {
               Name = "Exif", ContentType = string.Empty, FileExtensions = new[] { FileExtensions.Exif } 
            };

        /// <summary>
        ///   The flv.
        /// </summary>
        public static readonly MimeType FLV = new MimeType
            {
               Name = "FLV", ContentType = "video/x-flv", FileExtensions = new[] { "flv" } 
            };

        /// <summary>
        ///   The flash.
        /// </summary>
        public static readonly MimeType Flash = new MimeType
            {
               Name = "Flash video", ContentType = "video/x-flv", FileExtensions = new[] { "flv" } 
            };

        /// <summary>
        ///   The gp mobile.
        /// </summary>
        public static readonly MimeType GPMobile = new MimeType
            {
               Name = "3GP Mobile", ContentType = "video/3gpp", FileExtensions = new[] { "3gp" } 
            };

        /// <summary>
        ///   The gif.
        /// </summary>
        public static readonly MimeType Gif = new MimeType
            {
                Name = "Graphics Interchange Format", 
                ContentType = "image/gif", 
                FileExtensions = new[] { FileExtensions.Gif }
            };

        /// <summary>
        ///   The html.
        /// </summary>
        public static readonly MimeType Html = new MimeType
            {
               Name = "HyperText Markup Language (HTML)", ContentType = "text/html", FileExtensions = new[] { "html" } 
            };

        /// <summary>
        ///   The i phone index.
        /// </summary>
        public static readonly MimeType IPhoneIndex = new MimeType
            {
               Name = "iPhone Index", ContentType = "application/x-mpegURL", FileExtensions = new[] { "m3u8" } 
            };

        /// <summary>
        ///   The i phone segment.
        /// </summary>
        public static readonly MimeType IPhoneSegment = new MimeType
            {
               Name = "iPhone Segment", ContentType = "video/MP2T", FileExtensions = new[] { "ts" } 
            };

        /// <summary>
        ///   The icon.
        /// </summary>
        public static readonly MimeType Icon = new MimeType
            {
               Name = "Icon Image", ContentType = "image/x-icon", FileExtensions = new[] { FileExtensions.Icon } 
            };

        /// <summary>
        ///   The jpg.
        /// </summary>
        public static readonly MimeType Jpg = new MimeType
            {
                Name = "JPEG Image", 
                ContentType = "image/jpeg", 
                FileExtensions = new[] { FileExtensions.Jpeg, FileExtensions.Jpg }
            };

        /// <summary>
        ///   The mp 4.
        /// </summary>
        public static readonly MimeType Mp4 = new MimeType
            {
               Name = "MPEG-4 Video", ContentType = "video/mp4", FileExtensions = new[] { "mp4" } 
            };

        /// <summary>
        ///   The mpeg.
        /// </summary>
        public static readonly MimeType Mpeg = new MimeType
            {
               Name = "MPEG Video", ContentType = "video/mpeg", FileExtensions = new[] { "mpeg", "mpg" } 
            };

        /// <summary>
        ///   The pdf.
        /// </summary>
        public static readonly MimeType Pdf = new MimeType
            {
                Name = "Adobe Portable Document Format", 
                ContentType = "application/pdf", 
                FileExtensions = new[] { "pdf" }
            };

        /// <summary>
        ///   The png.
        /// </summary>
        public static readonly MimeType Png = new MimeType
            {
                Name = "Portable Network Graphics (PNG)", 
                ContentType = "image/png", 
                FileExtensions = new[] { FileExtensions.Png }
            };

        /// <summary>
        ///   The psd.
        /// </summary>
        public static readonly MimeType Psd = new MimeType
            {
               Name = "Photoshop Document", ContentType = "image/vnd.adobe.photoshop", FileExtensions = new[] { "psd" } 
            };

        /// <summary>
        ///   The quick time.
        /// </summary>
        public static readonly MimeType QuickTime = new MimeType
            {
               Name = "QuickTime", ContentType = "video/quicktime", FileExtensions = new[] { "mov" } 
            };

        /// <summary>
        ///   The swf.
        /// </summary>
        public static readonly MimeType Swf = new MimeType
            {
               Name = "Adobe Flash", ContentType = "application/x-shockwave-flash", FileExtensions = new[] { "swf" } 
            };

        /// <summary>
        ///   The tiff.
        /// </summary>
        public static readonly MimeType Tiff = new MimeType
            {
                Name = "Tagged Image File Format", 
                ContentType = "image/tiff",
					 FileExtensions = new[] { FileExtensions.Tif, FileExtensions.Tiff }
            };

        /// <summary>
        ///   The txt.
        /// </summary>
        public static readonly MimeType Txt = new MimeType
            {
               Name = "Text File", ContentType = "text/plain", FileExtensions = new[] { "txt" } 
            };

        /// <summary>
        ///   The windows media.
        /// </summary>
        public static readonly MimeType WindowsMedia = new MimeType
            {
               Name = "QuickTime", ContentType = "video/x-ms-wmv", FileExtensions = new[] { "wmv" } 
            };

        /// <summary>
        ///   The wmf.
        /// </summary>
        public static readonly MimeType Wmf = new MimeType
            {
                Name = "Microsoft Windows Metafile", 
                ContentType = "application/x-msmetafile", 
                FileExtensions = new[] { FileExtensions.Wmf }
            };

        /// <summary>
        ///   The _by content type.
        /// </summary>
        private static readonly Dictionary<string, MimeType> _byContentType = new Dictionary<string, MimeType>();

        #endregion

        #region Constructors and Destructors

        /// <summary>
        ///   Initializes static members of the <see cref="MimeTypes" /> class.
        /// </summary>
        static MimeTypes()
        {
            Register(Jpg);
            Register(Gif);
				Register(Png);
            Register(Tiff);
            Register(Bmp);
            Register(Exif);
            Register(Emf);
            Register(Icon);
            Register(Wmf);
            Register(Doc);
            Register(Psd);
            Register(Html);
            Register(Mpeg);
            Register(Mp4);
            Register(Pdf);
            Register(Swf);
            Register(Txt);
            Register(Flash);
            Register(GPMobile);
            Register(IPhoneIndex);
            Register(IPhoneSegment);
            Register(QuickTime);
            Register(AVInterleave);
            Register(WindowsMedia);
            Images = new[] { Jpg, Gif, Png, Tiff, Bmp, Icon, Psd };
            Documents = new[] { Doc, Pdf, Txt };
            Videos = new[] { Mpeg, Mp4, QuickTime, AVInterleave, WindowsMedia, FLV };
        }

        #endregion

        #region Public Properties

        /// <summary>
        ///   The documents.
        /// </summary>
        public static MimeType[] Documents { get; private set; }

        /// <summary>
        ///   The images.
        /// </summary>
        public static MimeType[] Images { get; private set; }

        /// <summary>
        ///   The videos.
        /// </summary>
        public static MimeType[] Videos { get; private set; }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// The get by content type.
        /// </summary>
        /// <param name="contentType">
        /// The content type. 
        /// </param>
        /// <param name="action">
        /// The action. 
        /// </param>
        /// <returns>
        /// The <see cref="MimeType"/> . 
        /// </returns>
        /// <exception cref="NotExistsException">
        /// </exception>
        public static MimeType GetByContentType(
            string contentType, NotExistsAction action = NotExistsAction.ThrowException)
        {
            var separatorIndex = contentType.IndexOf(";", StringComparison.Ordinal);
            if (separatorIndex >= 0)
            {
                contentType = contentType.Substring(0, separatorIndex);
            }

            MimeType mimeType = null;
            _byContentType.TryGetValue(contentType, out mimeType);

            if (mimeType == null && action == NotExistsAction.ThrowException)
            {
                throw new NotExistsException("Mime type doesn't exist for content type <" + contentType + ">");
            }

            return mimeType;
        }

        // TODO Add multiple extensions
        /// <summary>
        /// The get by extension.
        /// </summary>
        /// <param name="extension">
        /// The extension. 
        /// </param>
        /// <param name="action">
        /// The action. 
        /// </param>
        /// <returns>
        /// The <see cref="MimeType"/> . 
        /// </returns>
        /// <exception cref="NotExistsException">
        /// </exception>
        public static MimeType GetByExtension(string extension, NotExistsAction action = NotExistsAction.ThrowException)
        {
            var mimeType =
                _byContentType.FirstOrDefault(
                    pair =>
                    pair.Value.FileExtensions.Any(
                        e => string.Compare(e, extension, StringComparison.OrdinalIgnoreCase) == 0)).Value;

            if (mimeType == null && action == NotExistsAction.ThrowException)
            {
                throw new NotExistsException("Mime type doesn't exist for extension <" + extension + ">");
            }

            return mimeType;
        }

        /// <summary>
        /// The register.
        /// </summary>
        /// <param name="mimeType">
        /// The mime type. 
        /// </param>
        public static void Register(MimeType mimeType)
        {
            if (!string.IsNullOrEmpty(mimeType.ContentType))
            {
                _byContentType.Add(mimeType.ContentType, mimeType);
            }
        }

        /// <summary>
        /// The to string.
        /// </summary>
        /// <param name="mimeTypes">
        /// The mime types. 
        /// </param>
        /// <returns>
        /// The <see cref="string"/> . 
        /// </returns>
        public static string ToString(IEnumerable<MimeType> mimeTypes)
        {
            var builder = new StringBuilder();

            var isNotFirst = false;
            foreach (var mimeType in mimeTypes)
            {
                if (isNotFirst)
                {
                    builder.Append(";");
                }

                builder.Append(mimeType);
                isNotFirst = true;
            }

            return builder.ToString();
        }

        #endregion
    }
}